/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  */
	
/*
SCREEN:
GND->GND
vcc->5v
scl->A5
sda->A7
res->B0
DC ->B10
CS ->B1
BL ->B11

MAX30102:
GND->GND
SCL->B6
SDA->B7
VIN->3.3V
*/
	
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "i2c.h"
#include "spi.h"
#include "usart.h"
#include "usb_device.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "string.h"
#include "stdio.h"
#include "st7735.h"
#include "MAX30102.h"
#include "usbd_cdc_if.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
const uint16_t HEART[] = {
0x2100,0x0000,0x0008,0x2000,0x2000,0x8010,0xE018,0xC148,
0xE260,0x6359,0xC028,0x2000,0x4000,0x0000,0x0108,0x0108,
0x4000,0x2000,0x0008,0xC228,0x0339,0x8138,0x8040,0x8038,
0xE328,0x4008,0x4110,0x0000,0x0200,0x2100,0x0000,0x4100,
0x2000,0x2000,0x8130,0x4268,0x2398,0xA6B0,0xE6B8,0x48C1,
0x8490,0x8368,0x2028,0x0000,0x0000,0x2100,0x0000,0x2008,
0x8238,0xE578,0x28B1,0x07C9,0xA6C0,0xA5B8,0xE490,0xC370,
0xC250,0xA228,0x2100,0x4000,0x0000,0x0008,0x4008,0x2150,
0x6390,0x67B9,0xADF2,0xF1F3,0x13E5,0xD6F5,0x55FD,0x8CCA,
0xA578,0x6551,0x8008,0x0000,0xC120,0x8468,0xC9A1,0x31E4,
0x93FC,0xF6FD,0x17FE,0xCAF9,0x63E0,0x04D1,0x0499,0x6571,
0xC118,0x4000,0x0000,0x4010,0x4258,0x64B0,0x2DE3,0xF6FD,
0x99FE,0x19FF,0x59F7,0x19F7,0x5BFF,0xDAFE,0xF1D3,0x6791,
0x697A,0xA742,0xE478,0x8BC2,0xD6FD,0xB8FE,0xF5F5,0x79FF,
0xF7FE,0x6AEA,0xA2E8,0xE4E8,0xC4C8,0x26A9,0xC138,0x6000,
0x2000,0x8128,0x44A0,0x4EF3,0x17F7,0x34F6,0x50EC,0xD1EC,
0xD2FC,0x75FD,0xD5E5,0xF9F6,0x1BFF,0x8FDB,0x4ABA,0x8DCB,
0xEAC9,0x57FE,0xF8F6,0x36F6,0xB4ED,0x11ED,0x70FC,0xCADA,
0x23D9,0xC3E0,0xC5E0,0xE6D0,0xC468,0x0129,0x0229,0x2270,
0x0AD2,0x97FE,0xB2ED,0xC7D9,0x8AEA,0x50FC,0xB1FC,0x33F5,
0xF5F5,0xD6F5,0x38FE,0x58FE,0xABD2,0x85D0,0x75FD,0xF9FE,
0x77FE,0x53FD,0x94FD,0x52FD,0x4FF4,0x0EEC,0x25E1,0xC4E0,
0xE5E8,0xE6E0,0x0599,0x6461,0x2351,0x64A8,0x51FC,0x15F6,
0x87D9,0x03E8,0x2BFB,0xAFF4,0xEFE4,0x11FD,0x13FD,0xD6FD,
0x57F6,0x98FE,0xB1EC,0xEBD2,0xB8F6,0x17FE,0xB5F5,0xD5FD,
0xD2FC,0x90F4,0xF1FC,0xCEFB,0x06E1,0xE5E0,0xC4D8,0xC4D0,
0xE5B8,0x0489,0x2479,0x87A9,0x33FD,0x8EEB,0x63C8,0x05D9,
0x27DA,0x8EFC,0x8EFC,0x8FFC,0x33FD,0x54F5,0xF6F5,0xD5F5,
0xF6FD,0xB4FD,0x77F6,0x75FD,0x34FD,0x53F5,0x12F5,0xF1EC,
0x4FEC,0xEBFA,0xA5D8,0x25D9,0x03D9,0x23C9,0x24D1,0xE2A0,
0xA388,0x27BA,0xF0FC,0x85D1,0xA4E0,0x05D1,0x05E1,0x88FA,
0x4FFC,0x90FC,0xF1FC,0x32F5,0x72F5,0x94F5,0x94FD,0x74FD,
0x93F5,0x93F5,0x72ED,0x31ED,0xF1F4,0x6FFC,0xEBF2,0x86D9,
0xC5E8,0xE4C8,0xC4D0,0xE5C8,0xE6C8,0x25A1,0x2589,0xE7B9,
0x4EF4,0x45D1,0xC4D8,0x25D1,0xC4E0,0x64D9,0xA9E2,0x8CF3,
0x70FC,0xF1FC,0x12F5,0x12ED,0x12F5,0x32F5,0x32F5,0x32F5,
0xF1FC,0x90FC,0xCEFB,0xCAFA,0xA7E9,0xA4E0,0xC5E0,0x25D1,
0x04D1,0x05C9,0x06C9,0xE490,0x4569,0x86A9,0x2BEB,0x24D1,
0xE4D0,0x25D1,0xC4E0,0xC2D0,0xE4D0,0x86E1,0x69EA,0x4CF3,
0xEEFB,0x70FC,0x91FC,0xB1FC,0x70FC,0x0EFC,0x6CFB,0xAAF2,
0xC7E9,0x04E1,0xA3E0,0xA3E8,0xE5D8,0x04D9,0x45D1,0x05C9,
0x05B9,0x0379,0xC238,0x0591,0x49E2,0x25D1,0x04C9,0x25C9,
0xE5E8,0xC3E0,0xA3E8,0xA3E0,0xA3D8,0x04D9,0x86E1,0xC7E1,
0xC7E1,0xC7E1,0xA7E1,0x45E1,0xE4E0,0xC4E0,0xC4E0,0xA3D8,
0xE3D0,0x44D9,0xE5D8,0xC3C0,0x24C1,0xC5C8,0xC5A8,0xC150,
0x8218,0x0579,0xE8D1,0x25C9,0x25C9,0x05C9,0xE5E0,0xC4E0,
0xE4E8,0xC4E8,0xC4E0,0xC4E0,0xC4E0,0xA4E0,0xA4E8,0xA4E8,
0xE4E0,0xC4E8,0xA4E8,0xC4E8,0xE4E8,0x04D9,0x44D1,0x64C9,
0xC4D0,0xA6C9,0x44B9,0xC5C8,0xC490,0x6018,0x6108,0xE450,
0x66A9,0x45C1,0x45C9,0x05C9,0xE5D0,0xE4D0,0xE4D0,0x04D1,
0x04D9,0x05E1,0xE4E0,0xC4E0,0xA4E8,0xC4F0,0x04D9,0x04D9,
0xE4E0,0xC4E0,0xC4D8,0xE4D0,0x04D1,0x04C9,0xC4C0,0xADEB,
0xE7C1,0xE6C0,0xC470,0x6000,0x0100,0x8120,0x0379,0x24B1,
0x05C9,0xE5C8,0x25C1,0x05C9,0x25D1,0x04D1,0x04D1,0x05D9,
0x04D9,0xE4D8,0xE4E0,0xE4E0,0x04D1,0x04D1,0x25D9,0x25D9,
0x05D9,0x05D9,0xE4D0,0xE4D0,0xA7C1,0x50F4,0xC8C9,0xE598,
0xC340,0x4000,0x0100,0x4008,0xE158,0x24A9,0xC4C0,0xC5C8,
0x45B9,0x05C1,0x05D1,0xE4D0,0xE5D0,0xE5D8,0xE4D8,0xC4D8,
0xE4D0,0x04D9,0xE4E0,0xC4D8,0xC3D0,0x04D1,0x25D1,0x04C9,
0xE4C8,0xC4C8,0xCBD2,0x4CD3,0xC5B8,0x8378,0xE220,0x2000,
0x0100,0x2000,0x8110,0xE460,0x06A9,0xE5C0,0x04C1,0x24C1,
0x24C9,0x03C9,0x04C9,0x05D1,0xE5D0,0xE5D0,0x05D1,0xE4C8,
0x03C9,0x25D1,0x25D1,0x05D1,0x26D1,0x06C9,0x05C1,0x26C1,
0xACDB,0x48D1,0xE570,0xE328,0x6000,0x0010,0x0100,0x0000,
0x2008,0x8238,0xE480,0x05B1,0x05C1,0x24C1,0x64C1,0x24C1,
0x24C1,0x25C9,0x04C1,0x05C9,0x05D1,0xE4D0,0xE4D0,0x04C9,
0x04B9,0x04B9,0x05C9,0xA4C0,0x46C1,0x8AD2,0x49D2,0xE5A0,
0x0559,0x2110,0x2000,0x4008,0x2000,0x0000,0x0000,0x2008,
0xA240,0x0589,0x05B9,0x04B9,0x24B1,0x04B1,0x04B9,0x24B9,
0x24B9,0x25C1,0x25C9,0xE5D0,0xE4D0,0x04C1,0x24B9,0x45B9,
0x05C1,0xE5C0,0xA7C1,0xEAD2,0x06B1,0xC468,0x6228,0x0008,
0x0000,0x4000,0x0000,0x0000,0x0000,0x0000,0x8118,0xE358,
0x0599,0x05B9,0x25C1,0x05C1,0x25C1,0x25C1,0x45B9,0x45B9,
0x05C1,0xC5C8,0xE4C0,0x05C1,0x45C9,0x04B9,0xE4B8,0x86C1,
0xE8C9,0xA7B9,0xE580,0xC230,0x0000,0x0000,0x4100,0x2000,
0x0000,0x0000,0x0000,0x0000,0x2000,0x8120,0xE460,0x06A1,
0xC6B8,0xE6C0,0xE5C8,0xE4C0,0x04B9,0x45B1,0x25B9,0xE5B8,
0x05B9,0x05B9,0x05C1,0xE4B8,0x04B9,0xC7C1,0xA7B1,0xA388,
0x0439,0x4000,0x0008,0x0000,0x2100,0x0000,0x0000,0x0000,
0x2000,0x0000,0x0000,0x2000,0xA230,0x0569,0x0699,0x06B1,
0xE5C0,0xC4B8,0xE4B0,0x25A9,0x25B1,0x26B1,0x06B9,0x05B1,
0x24A9,0x45B9,0x87C1,0x87B1,0x2581,0xA350,0x8100,0x2000,
0x0008,0x0000,0x0000,0x0008,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x4108,0xA220,0x6569,0x8691,0x66B1,0x05B9,
0x24B9,0x45B1,0x25A9,0x26A9,0x26B1,0x25A9,0x45A9,0x86B1,
0x66A9,0xC478,0x8238,0xA210,0x2000,0x2000,0x0008,0x2000,
0x0000,0x0008,0x2000,0x0000,0x0008,0x0000,0x0000,0x0000,
0x0000,0x4000,0xA118,0x0351,0x0489,0x04A9,0x24B1,0x45A9,
0x25A9,0x06A9,0x45A1,0x45A9,0x45A9,0x0499,0x6168,0x0030,
0x2000,0x4100,0x0108,0x0008,0x4008,0x4000,0x0000,0x2008,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0100,0x6100,0xA220,0xC468,0x26A9,0x26B9,0x25A9,0x4599,
0x45A1,0x87B1,0x0581,0x6130,0x4000,0x2000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0100,0x0000,
0x2000,0xC120,0x8461,0xE7A9,0xC7B9,0xA6B1,0xA8C1,0x4699,
0x8248,0x0008,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x2000,0x2000,0x2000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0008,0x0008,0x0000,0x2000,
0xE130,0xA581,0xA6B1,0x45B9,0x48A9,0x0561,0x8118,0x2000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2000,
0x2000,0x2000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x2000,0x2000,0x0000,0x0018,0xC348,
0x6689,0x46A9,0x6669,0xA228,0x2000,0x2000,0x0000,0x0000,
0x0000,0x0008,0x0000,0x0000,0x0000,0x2000,0x2000,0x2000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0008,0x0000,0x0000,0x0000,0x0000,0x8100,0x2319,0x2331,
0xA220,0x4000,0x4000,0x2000,0x2108,0x0100,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2108,0x0008,
0x0000,0x0000,0x2000,0x0008,0x0008,0x2000,0x0020,0x0000,
0x2000,0x0000,0x0008,0x0008,0x0000,0x4000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,
};

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
  char str[64] = {'\0'};
  char heart_str[32] = {'\0'};

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();
  MX_I2C1_Init();
  MX_ADC1_Init();
  MX_USB_DEVICE_Init();
  /* USER CODE BEGIN 2 */
  int ret = Max30102_Init(&hi2c1); //初始化max30102传感器
  int delay = 100;
  int i = 0, j = 0;
  int clear_scr = 1;
  int hr_data = 0;
  
  ST7735_Init();                   //初始化显示屏，显示黑色背景
  ST7735_FillScreen(ST7735_BLACK);
                                   //显示标题，定义字体为11x18大小，红色字，黑色背景
  //ST7735_WriteString(5, 5, "Heart Rate", Font_11x18, ST7735_RED, ST7735_BLACK);
  for (i = 0; i < 5; i ++) {
    //显示中文标题，定义字体为12x16大小，红色字，黑色背景，字体宽度为12，X要每次增加
    ST7735_WriteCharChn(35 + j * 12, 5 , i, Font_12x16, ST7735_RED, ST7735_BLACK);
    j++;
  }

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {                                //每循环一次闪一下灯，表示程序正在运行
		HAL_GPIO_TogglePin(led_sys_GPIO_Port, led_sys_Pin);
		HAL_Delay(delay);
    if (ret == MAX30102_OK) {      //判断心率传感器是否初始化成功，并显示对应状态
      sprintf(str, " MAX30102 running");
      ST7735_WriteString(2, 25, str, Font_7x10, ST7735_YELLOW, ST7735_BLACK);
    } else {
      sprintf(str, " MAX30102 ERR !");
      ST7735_WriteString(2, 25, str, Font_7x10, ST7735_YELLOW, ST7735_BLACK);
    }
    //画框，上下紫色，左右红色
    for(int x = 0; x < ST7735_WIDTH; x++) {
      ST7735_DrawPixel(x, 0, ST7735_MAGENTA);
      ST7735_DrawPixel(x, ST7735_HEIGHT-1, ST7735_MAGENTA);
    }

    for(int y = 0; y < ST7735_HEIGHT; y++) {
      ST7735_DrawPixel(0, y, ST7735_RED);
      ST7735_DrawPixel(ST7735_WIDTH-1, y, ST7735_RED);
    }


    Max30102_Task();               //调用心率传感器任务函数，驱动会去读取传感器寄存器内的数值
    if (Max30102_IsFingerOnSensor() == 0) {
      clear_scr = 1;               //此变量用于判断是否需要清屏幕
      j = 0;
      for (i = 5; i <= 14; i ++) { //显示“请放置手指到传感器”
        ST7735_WriteCharChn(1 + j * 12, 100, i, Font_12x16, ST7735_RED, ST7735_BLACK);
        j++;                       // 变量j用于控制显示一个字后，x起始位置往后移动一个字的宽度
      }
    } else {
      if (clear_scr == 1) {
        for (j = 0; j < 10; j ++) {//清屏幕，前面字数比这里长，需要显示空白再显示字，否则字会叠在一起
          ST7735_WriteCharChn(1 + j * 12, 100, 22, Font_12x16, ST7735_RED, ST7735_BLACK);
        }
        clear_scr = 0;             //表示已经清过屏幕
      }
      j = 0;
      for (i = 15; i <= 17; i ++) {//显示“检测中”
        ST7735_WriteCharChn(1 + j * 12, 100, i, Font_12x16, ST7735_RED, ST7735_BLACK);
        j++;
      }
    }


    //将心率整型数值转换成字符串，方便显示到屏幕上
    hr_data = Max30102_GetHeartRate();
    sprintf(heart_str, ":%d    ", hr_data);
    ST7735_WriteCharChn(1 + 0, 48, 0, Font_12x16, ST7735_RED, ST7735_BLACK);
    ST7735_WriteCharChn(1 + 12, 48, 1, Font_12x16, ST7735_RED, ST7735_BLACK);
    ST7735_WriteString(30, 48, heart_str, Font_11x18, ST7735_RED, ST7735_BLACK);


    //显示心形图案到屏幕上，其中图案数据在HEART数组内
    ST7735_DrawImage(95, 70, 30, 30, HEART);
    
    
    //显示心情
    if (hr_data <= 70) {
        //低沉
        ST7735_WriteCharChn(50 + 0, 80, 23, Font_12x16, ST7735_RED, ST7735_BLACK);
        ST7735_WriteCharChn(50 + 12, 80, 24, Font_12x16, ST7735_RED, ST7735_BLACK);
    }
    else if (hr_data > 70 && hr_data <= 90) {
        //平静
        ST7735_WriteCharChn(50 + 0, 80, 25, Font_12x16, ST7735_RED, ST7735_BLACK);
        ST7735_WriteCharChn(50 + 12, 80, 26, Font_12x16, ST7735_RED, ST7735_BLACK);
    }
    else if (hr_data > 90 && hr_data <= 100) {
        //愉悦
        ST7735_WriteCharChn(50 + 0, 80, 27, Font_12x16, ST7735_RED, ST7735_BLACK);
        ST7735_WriteCharChn(50 + 12, 80, 28, Font_12x16, ST7735_RED, ST7735_BLACK);
    }
    else if (hr_data > 100 && hr_data <= 120) {
        //紧张
        ST7735_WriteCharChn(50 + 0, 80, 29, Font_12x16, ST7735_RED, ST7735_BLACK);
        ST7735_WriteCharChn(50 + 12, 80, 30, Font_12x16, ST7735_RED, ST7735_BLACK);
    }
    else if (hr_data > 120) {
        //躁郁
        ST7735_WriteCharChn(50 + 0, 80, 31, Font_12x16, ST7735_RED, ST7735_BLACK);
        ST7735_WriteCharChn(50 + 12, 80, 32, Font_12x16, ST7735_RED, ST7735_BLACK);
    }
    
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC|RCC_PERIPHCLK_USB;
  PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
  PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
